import axios from 'axios' // 引入axios工具
import store from '@/store'
import router from '@/router'

// 创建axios实例(service里面带前缀基地址和超时时间)
const service = axios.create({
  // 知识点：nodejs+webpack下的环境变量
  // process.env -> nodejs环境下的内置全局变量(任意处使用)
  // 效果：获取敲击命令，执行时的"环境变量"
  // yarn dev(开发环境启动)->process.env上会被nodejs+webpack挂载.env.development文件里变量值到这里
  // yarn build:prod(打包准备放入生产环境）->process.env上会被挂载.env.production文件里变量值到这里
  // 作用：根据敲击的代码，自动加载对应不同的环境变量，开发时是一个基地址，上线时是一个基地址
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // axios请求的完整地址：baseURL + url
  // 不能让axios直接去请求http://开头的外链地址，而是要请求/开头还得命中本地开发服务器里代理规则
  // 知识点：请求的路径问题
  // axios/script标签src/img标签的src/link的href.都会发一次请求
  // 如果是./开头的地址，找当前文件夹
  // 如果是http开头的地址，找到外链外部服务器(链接网络)
  // 如果是/开头的地址，忽略文件夹，直接找当前运行时，所在服务器
  timeout: 5000 // request timeout
})

// 请求
service.interceptors.request.use(
  config => {
    // js文件内不能使用this.$store，因为这个this关键字不是vue组件对象，无法查找原型链上$store
    const token = store.getters.token
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
// 知识点：axios内部的处理机制
// (1)：http状态为2xx，3xx，就会给Promise对象位置，返回成功的结果(resolve())
// (1)：http状态为4xx，5xx，就会给Promise对象位置，返回失败的结果(reject())
// 如果行要做一些操作，可以在axios的响应拦截器，自己来处理返回的结果
// 补充：http状态码，由本次请求后，后端进行设置返回的
service.interceptors.response.use(
  response => { // http为2xx，3xx进入这里
    // 本项目成功/失败都是2xx响应状态码，都进入这里，所以需要自己根据字段判断
    const { success, message } = response.data
    if (success === false) { // 失败
      return Promise.reject(new Error(message))
    } else { // 成功
      // response->返回的还是axios处理的结果对象(逻辑那边得.data.data)拿到后台返回值
      // response.data->返回的就是后台返回的响应对象(逻辑那边哪到哪真正的数据.data)拿到返回值
      return response.data // 特殊：返回的是axios调用在原地留下的"Promise"对象位置(逻辑页面await 后面)
    }
  },
  error => { // http为4xx，5xx进入这里
    // 身份过期，后台双重返回401，逻辑状态码
    // 前置非空判断(error有值，才会执行&&后面的代码)
    // 确保error有值，再.response，.response有值，再.status
    // 防止null.xxxx 语法报错代码停止
    // if (error && error.response && error.response.status === 401) {
    //  // 身份过期，删除所有cookie，重置vuex，强制回到登录页面
    // }
    // 但是账号密码失败的时候返回的是200，用逻辑判断 - 最好统一
    // code更好因为401如果有多个情况，success只能判断是失败，可以跟后台商量code值不同错误不同
    // 10000成功 10002身份过期 10004xxxx
    if (error.response.data.code === 10002) { // 身份验证
      store.commit('user/RESET_STATE')
      store.commit('user/REMOVE_TOKEN') // 内部会删除本地cookie里token
      router.replace(`/login?redirect=${router.currentRoute.fullPath}`)
    }
    return Promise.reject(error) // 相当于reject(error)
  }
)

export default service
